The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
.gitignore 01
Changes 06
MANIFEST 12
META.yml 11
README 11
calc.h 11
callback_stubs.inc 11
lib/HTML/Template/Pro/CommonTest.pm 1610
lib/HTML/Template/Pro.pm 11
loadfile.inc 55
pconst.h 01
perl-HTML-Template-Pro.spec 14
procore.c 512
procore.h 15
t/HTML/Template/Pro/CommonTest.pm 0172
t/HTML-Template-Expr.t 01
t/HTML-Template-Pro.t 01
t/error_output.t 019
tags.inc 77
templates-Pro/test_esc4.out 02
templates-Pro/test_esc4.tmpl 02
21 files changed (This is a version diff) 186245
@@ -14,6 +14,7 @@ pm_to_blib
 Makefile.old
 semantic.cache
 templates-Pro/json
+templates-Pro/json-cs
 getoptint.re2c.inc
 resetopt0.inc
 resetoptnot0.inc
@@ -293,3 +293,9 @@ Revision history for Perl extension HTML::Template::Pro.
 09502 Fri Jun 18 18:02:28 EEST 2010
 	- bugfix release: segfault for string operetions
 	with undefined variables. Thanks to Mike Shogin.
+
+09503 Sat Aug 28 18:00:49 EEST 2010
+	- log file is not truncated now in tmplpro_set_log_file.
+	- freed memory access error fixed.
+	- perl: CommonTest.pm hidden from installation
+	- tests: added generic json-packed test data 
@@ -27,7 +27,6 @@ exprtype.h
 exprval.h
 lib/HTML/Template/PerlInterface.pod
 lib/HTML/Template/Pro.pm
-lib/HTML/Template/Pro/CommonTest.pm
 lib/HTML/Template/Pro/WrapAssociate.pm
 lib/HTML/Template/SYNTAX.pod
 loadfile.h
@@ -65,9 +64,11 @@ t/03complex.t
 t/04register.t
 t/05path_like_variable_scope.t
 t/06loop_var.t
+t/error_output.t
 t/HTML-Template-Expr.t
 t/HTML-Template-Pro.t
 t/HTML-Template.t
+t/HTML/Template/Pro/CommonTest.pm
 t/magic.t
 t/pod.t
 t/realloc.t
@@ -1,6 +1,6 @@
 --- #YAML:1.0
 name:               HTML-Template-Pro
-version:            0.9502
+version:            0.9503
 abstract:           Perl/XS module to use HTML Templates from CGI scripts
 author:
     - I. Yu. Vlasenko <viy@altlinux.org>
@@ -1,4 +1,4 @@
-HTML-Template-Pro version 0.9502
+HTML-Template-Pro version 0.9503
 ==============================
 
 DESCRIPTION
@@ -14,7 +14,7 @@ typedef struct exprval (*func_t_ee) (struct expr_parser* exprobj, struct exprval
 struct symrec_const
 {
   char *name;  /* name of symbol */
-  int len;     /* symbol length */;
+  int len;     /* symbol length */
   int type;    /* type of symbol: either VAR or FNCT */
   double var;      /* value of a VAR */
   void* fnctptr;  /* value of a FNCT */
@@ -37,7 +37,7 @@ static void BACKCALL stub_write_chars_to_pbuffer (ABSTRACT_WRITER* state,const c
 }
 
 static ABSTRACT_USERFUNC* BACKCALL stub_is_expr_userfnc_func (ABSTRACT_FUNCMAP* af, PSTRING name) {
-  tmpl_log(TMPL_LOG_ERROR,"is_expr_userfnc_func stub: EXPR is not initialized properly. user func dispatcher was not supplied.");
+  tmpl_log(TMPL_LOG_DEBUG,"is_expr_userfnc_func stub: EXPR is not initialized properly. user func dispatcher was not supplied.\n");
   return NULL;
 }
 
@@ -1,161 +0,0 @@
-package HTML::Template::Pro::CommonTest;
-
-use strict;
-use warnings;
-use Carp;
-
-use Test;
-use File::Spec;
-use File::Path;
-use HTML::Template::Pro qw/:const/;
-#use Data::Dumper;
-use JSON;
-require Exporter;
-use vars qw/@ISA @EXPORT/;
-@ISA=qw/Exporter/;
-@EXPORT =qw/test_tmpl test_tmpl_std test_tmpl_expr dryrun/;
-
-use vars qw/$DumpDir/;
-$DumpDir='json';
-
-#$Data::Dumper::Terse=1;
-#$Data::Dumper::Indent=1;
-#$Data::Dumper::Useqq=1;
-#$Data::Dumper::Pair = ' : ';
-
-#########################
-
-my $DEBUG=$ENV{HTP_DEBUG};
-$DEBUG||=0;
-
-sub test_tmpl {
-    my $file=shift;
-    my $optref=shift;
-    my @param=@_;
-    my $tmpl;
-    print "\n--------------- Test: $file ---------------------\n";
-    chdir 'templates-Pro';
-    $tmpl=HTML::Template::Pro->new(filename=>$file.'.tmpl',debug=>$DEBUG, @$optref);
-    $tmpl->param(@param);
-    &dryrun($tmpl,$file);
-    $ENV{HTP_DUMP} && &dump_test ($file,{@$optref},{@param});
-    chdir '..';
-}
-
-sub test_tmpl_expr {
-    my $file=shift;
-    my $tmpl;
-    print "\n--------------- Test: $file ---------------------\n";
-    chdir 'templates-Pro';
-    $tmpl=HTML::Template::Pro->new(filename=>$file.'.tmpl', loop_context_vars=>1, case_sensitive=>1,tmpl_var_case=>ASK_NAME_UPPERCASE|ASK_NAME_AS_IS,debug=>$DEBUG, functions=>{'hello' => sub { return "hi, $_[0]!" }});
-    $tmpl->param(@_);
-    # per-object extension
-    $tmpl->register_function('per_object_call' => sub { return shift()."-arg"});
-    $tmpl->register_function('perobjectcall2' => sub { return shift()."-arg"});
-    &dryrun($tmpl,$file);
-    chdir '..';
-}
-
-my $case_ext = [
-    loop_context_vars=>1,
-    case_sensitive=>0,
-    ];
-my $case_int = [
-    loop_context_vars=>1,
-    case_sensitive=>1,
-    tmpl_var_case=>ASK_NAME_UPPERCASE,
-    ];
-
-sub test_tmpl_std {
-    my ($file,@args)=@_;
-    &test_tmpl($file, $case_ext, @args);
-    &test_tmpl($file, $case_int, @args);
-}
-
-sub dryrun {
-    my $tmpl=shift;
-    my $file=shift;
-    open (OUTFILE, ">$file.raw") || die "can't open $file.raw: $!";
-    binmode (OUTFILE);
-    $tmpl->output(print_to => *OUTFILE);
-    close (OUTFILE) || die "can't close $file.raw: $!";
-    my $fileout = &catfile("$file.out");
-    my $files_equal=&catfile("$file.raw") eq $fileout;
-    if ($files_equal) {
-	ok($files_equal) && unlink "$file.raw";
-    } else {
-	if (-x '/usr/bin/diff') {
-	    print STDERR `diff -u $file.out $file.raw`;
-	} else {
-	    print STDERR "# >>> ---$file.raw---\nTODO: diff here\n>>> ---end $file.raw---\n";
-	}
-    }
-    my $output=$tmpl->output();
-    ok (defined $output and $output eq $fileout);
-}
-
-sub catfile {
-    my $file=shift;
-    open (INFILE, $file) || die "can't open $file: $!";
-    binmode (INFILE);
-    local $/;
-    my $catfile=<INFILE>;
-    close (INFILE) || die "can't close $file: $!";
-    return $catfile;
-}
-
-my %filename_counter;
-$0=~/([\w_-]+)(?:\.t)$/;
-my $dump_prefix = $1 ? "$1-" : '';
-sub _dump_file_name {
-    my ($file) = @_;
-    my $plain=$file;
-    $plain=~s![\\/:]!_!g;
-    return File::Spec->catfile($DumpDir, 
-      $dump_prefix.$plain.'-'.sprintf("%.2d",++$filename_counter{$file}).'.json');
-}
-
-sub dump_test {
-    my ($file,$optref,$paramref) = @_;
-    mkpath ($DumpDir);
-    my $dump_file = _dump_file_name($file);
-    open FH, '>', $dump_file or die "can't open ($!) ".$dump_file;
-    my $tojson = {
-	'file' => $file,
-	'options' => $optref,
-	'params' => $paramref,
-    };
-    print FH to_json($tojson, {utf8 => 1, pretty => 1});
-    close (FH) or die "can't close ($!) ".$dump_file;
-}
-
-### Local Variables: 
-### mode: perl
-### End: 
-
-
-1;
-
-__END__
-
-#head1 NAME
-
-HTML::Template::Pro::CommonTest - internal common test library
-
-#head1 DESCRIPTION
-
-internal common test library
-
-#head1 AUTHOR
-
-I. Vlasenko, E<lt>viy@altlinux.orgE<gt>
-
-#head1 COPYRIGHT AND LICENSE
-
-Copyright (C) 2009 by I. Yu. Vlasenko.
-
-This library is free software; you can redistribute it and/or modify it under 
-either the LGPL2+ or under the same terms as Perl itself, either Perl version 5.8.4 
-or, at your option, any later version of Perl 5 you may have available.
-
-#cut
@@ -12,7 +12,7 @@ require Exporter;
 use vars qw($VERSION @ISA @EXPORT_OK %EXPORT_TAGS);
 @ISA = qw(DynaLoader Exporter);
 
-$VERSION = '0.9502';
+$VERSION = '0.9503';
 
 @EXPORT_OK = qw/ASK_NAME_DEFAULT ASK_NAME_AS_IS ASK_NAME_LOWERCASE ASK_NAME_UPPERCASE ASK_NAME_MASK/;
 %EXPORT_TAGS = (const => [qw/ASK_NAME_DEFAULT ASK_NAME_AS_IS ASK_NAME_LOWERCASE ASK_NAME_UPPERCASE ASK_NAME_MASK/]);
@@ -139,8 +139,8 @@ mmap_load_file (const char* filepath) {
   stream = fopen(filepath, "r");
   if (stream == NULL) return memarea; /* {NULL,NULL} */
   /* mmap size_in_bytes+1 to avoid crash with empty file */
-  memarea.begin=(char*) malloc(memsize+1);
-  writepoint=memarea.begin;
+  memarea.begin=(const char*) malloc(memsize+1);
+  writepoint=(char*)memarea.begin;
 
   while (1) {
     realsize=fread(writepoint, 1, chunksize, stream);
@@ -149,8 +149,8 @@ mmap_load_file (const char* filepath) {
       writepoint+=chunksize;
       if (size_in_bytes+chunksize>memsize) {
 	memsize*=2;
-	memarea.begin=(char*) realloc(memarea.begin, memsize+1);
-	writepoint=memarea.begin+size_in_bytes;
+	memarea.begin=(char*) realloc((char*)memarea.begin, memsize+1);
+	writepoint=((char*)memarea.begin)+size_in_bytes;
       }
     } else {
       fclose(stream);
@@ -164,7 +164,7 @@ static
 int 
 mmap_unload_file (PSTRING memarea) {
   /* destroying */
-  free(memarea.begin);
+  free((char*)memarea.begin);
   return 0;
 }
 
@@ -7,6 +7,7 @@
 #define ERR_PRO_FILE_NOT_FOUND 2
 #define ERR_PRO_CANT_OPEN_FILE 3
 #define ERR_PRO_TEMPLATE_SYNTAX_ERROR 4
+#define ERR_PRO_NOT_ENOUGH_MEMORY 5
 
 #endif /* pconst.h */
 
@@ -6,7 +6,7 @@
 %define module HTML-Template-Pro
 
 Name: perl-%module
-Version: 0.9502
+Version: 0.9503
 Release: alt1
 
 Packager: Igor Yu. Vlasenko <viy@altlinux.org>
@@ -54,6 +54,9 @@ in the Perl script.
 %perl_vendor_man3dir/*
 
 %changelog
+* Sat Aug 28 2010 Igor Vlasenko <viy@altlinux.ru> 0.9503-alt1
+- new version; see Changes
+
 * Thu Jun 17 2010 Igor Vlasenko <viy@altlinux.ru> 0.9502-alt1
 - new version; see Changes
 
@@ -429,6 +429,7 @@ tmplpro_exec_tmpl_filename (struct tmplpro_param *param, const char* filename)
   int mmapstatus;
   PSTRING memarea;
   int retval = 0;
+  const char* saved_masterpath;
   /* 
    * param->masterpath is path to upper level template 
    * (or NULL in toplevel) which called <include filename>.
@@ -439,7 +440,8 @@ tmplpro_exec_tmpl_filename (struct tmplpro_param *param, const char* filename)
   if (NULL==filepath) return ERR_PRO_FILE_NOT_FOUND;
   /* filepath should be alive for every nested template */
   filepath = strdup(filepath);
-
+  if (NULL==filepath) return ERR_PRO_NOT_ENOUGH_MEMORY;
+  saved_masterpath=param->masterpath; /* saving current file name */
   param->masterpath=filepath;
   if (param->filters) memarea=(param->LoadFileFuncPtr)(param->ext_filter_state,filepath);
   else memarea=mmap_load_file(filepath);
@@ -460,6 +462,7 @@ tmplpro_exec_tmpl_filename (struct tmplpro_param *param, const char* filename)
   else mmapstatus=mmap_unload_file(memarea);
  cleanup_filepath:
   if (filepath!=NULL) free((void*) filepath);
+  param->masterpath=saved_masterpath;
   return retval;
 }
 
@@ -468,12 +471,16 @@ int
 tmplpro_exec_tmpl_scalarref (struct tmplpro_param *param, PSTRING memarea)
 {
   struct tmplpro_state state;
+  const char* saved_masterpath=param->masterpath; /* saving current file name */
   param->masterpath=NULL; /* no upper file */
   state.top = memarea.begin;
   state.next_to_end=memarea.endnext;
-  if (memarea.begin == memarea.endnext) return 0;
-  init_state(&state,param);
-  process_state(&state);
+  if (memarea.begin != memarea.endnext) {
+    init_state(&state,param);
+    process_state(&state);
+  }
+  /* exit cleanup code */
+  param->masterpath=saved_masterpath;
   return 0;
 }
 
@@ -694,7 +701,7 @@ tmplpro_set_log_file(struct tmplpro_param* param, const char* logfilename)
     tmpl_log_set_callback(tmpl_log_default_callback);
     return 0;
   }
-  file_p = fopen(logfilename, "w");
+  file_p = fopen(logfilename, "a");
   if (!file_p) {
     tmpl_log(TMPL_LOG_ERROR,"tmplpro_set_log_file: can't create log file [%s]\n",logfilename);
     return ERR_PRO_FILE_NOT_FOUND;
@@ -12,7 +12,11 @@ static const char* const errlist[] = {
   "invalid argument",
   "file not found",
   "can't open file",
-  "syntax error in template"
+  "syntax error in template",
+  "not enough memory (allocation error)",
+  "",
+  "",
+  ""
 };
 
 /* 
@@ -0,0 +1,172 @@
+package HTML::Template::Pro::CommonTest;
+
+use strict;
+use warnings;
+use Carp;
+
+use Test;
+use File::Spec;
+use File::Path;
+use HTML::Template::Pro qw/:const/;
+#use Data::Dumper;
+use JSON;
+require Exporter;
+use vars qw/@ISA @EXPORT/;
+@ISA=qw/Exporter/;
+@EXPORT =qw/test_tmpl test_tmpl_std test_tmpl_expr dryrun/;
+
+use vars qw/$DumpDir $DumpDir_no_cs/;
+$DumpDir='json-cs';
+$DumpDir_no_cs='json';
+
+#$Data::Dumper::Terse=1;
+#$Data::Dumper::Indent=1;
+#$Data::Dumper::Useqq=1;
+#$Data::Dumper::Pair = ' : ';
+
+#########################
+
+my $DEBUG=$ENV{HTP_DEBUG};
+$DEBUG||=0;
+
+sub test_tmpl {
+    my $file=shift;
+    my $optref=shift;
+    my @param=@_;
+    my $tmpl;
+    print "\n--------------- Test: $file ---------------------\n";
+    chdir 'templates-Pro';
+    $tmpl=HTML::Template::Pro->new(filename=>$file.'.tmpl',debug=>$DEBUG, @$optref);
+    $tmpl->param(@param);
+    &dryrun($tmpl,$file);
+    $ENV{HTP_DUMP} && &dump_test ($file,{@$optref},{@param});
+    chdir '..';
+}
+
+sub test_tmpl_expr {
+    my $file=shift;
+    my $tmpl;
+    print "\n--------------- Test: $file ---------------------\n";
+    chdir 'templates-Pro';
+    $tmpl=HTML::Template::Pro->new(filename=>$file.'.tmpl', loop_context_vars=>1, case_sensitive=>1,tmpl_var_case=>ASK_NAME_UPPERCASE|ASK_NAME_AS_IS,debug=>$DEBUG, functions=>{'hello' => sub { return "hi, $_[0]!" }});
+    $tmpl->param(@_);
+    # per-object extension
+    $tmpl->register_function('per_object_call' => sub { return shift()."-arg"});
+    $tmpl->register_function('perobjectcall2' => sub { return shift()."-arg"});
+    &dryrun($tmpl,$file);
+    chdir '..';
+}
+
+my $case_ext = [
+    loop_context_vars=>1,
+    case_sensitive=>0,
+    ];
+my $case_int = [
+    loop_context_vars=>1,
+    case_sensitive=>1,
+    tmpl_var_case=>ASK_NAME_UPPERCASE,
+    ];
+
+sub test_tmpl_std {
+    my ($file,@args)=@_;
+    &test_tmpl($file, $case_ext, @args);
+    &test_tmpl($file, $case_int, @args);
+}
+
+sub dryrun {
+    my $tmpl=shift;
+    my $file=shift;
+    open (OUTFILE, ">$file.raw") || die "can't open $file.raw: $!";
+    binmode (OUTFILE);
+    $tmpl->output(print_to => *OUTFILE);
+    close (OUTFILE) || die "can't close $file.raw: $!";
+    my $fileout = &catfile("$file.out");
+    my $files_equal=&catfile("$file.raw") eq $fileout;
+    if ($files_equal) {
+	ok($files_equal) && unlink "$file.raw";
+    } else {
+	if (-x '/usr/bin/diff') {
+	    print STDERR `diff -u $file.out $file.raw`;
+	} else {
+	    print STDERR "# >>> ---$file.raw---\nTODO: diff here\n>>> ---end $file.raw---\n";
+	}
+    }
+    my $output=$tmpl->output();
+    ok (defined $output and $output eq $fileout);
+}
+
+sub catfile {
+    my $file=shift;
+    open (INFILE, $file) || die "can't open $file: $!";
+    binmode (INFILE);
+    local $/;
+    my $catfile=<INFILE>;
+    close (INFILE) || die "can't close $file: $!";
+    return $catfile;
+}
+
+my %filename_counter;
+$0=~/([\w_-]+)(?:\.t)$/;
+my $dump_prefix = $1 ? "$1-" : '';
+sub _dump_file_name {
+    my ($DumpDir,$file) = @_;
+    my $plain=$file;
+    $plain=~s![\\/:]!_!g;
+    return File::Spec->catfile($DumpDir, 
+      $dump_prefix.$plain.'-'.sprintf("%.2d",++$filename_counter{$file}).'.json');
+}
+
+sub dump_test {
+    my ($file,$optref,$paramref) = @_;
+    mkpath ([$DumpDir,$DumpDir_no_cs]);
+    my $tojson = {
+	'file' => $file,
+	'options' => $optref,
+	'params' => $paramref,
+    };
+    &__dump_json(&_dump_file_name($DumpDir,$file), $tojson);
+    my $case_sensitive=$optref->{'case_sensitive'};
+    if (defined $case_sensitive) {
+	delete $optref->{'case_sensitive'};
+	$optref->{'tmpl_var_case'}=ASK_NAME_UPPERCASE unless $case_sensitive;
+    }
+    &__dump_json(&_dump_file_name($DumpDir_no_cs,$file), $tojson);
+}
+
+sub __dump_json {
+    my ($dump_file, $tojson) = @_;
+    open FH, '>', $dump_file or die "can't open ($!) ".$dump_file;
+    print FH to_json($tojson, {utf8 => 1, pretty => 1});
+    close (FH) or die "can't close ($!) ".$dump_file;
+}
+
+### Local Variables: 
+### mode: perl
+### End: 
+
+
+1;
+
+__END__
+
+#head1 NAME
+
+HTML::Template::Pro::CommonTest - internal common test library
+
+#head1 DESCRIPTION
+
+internal common test library
+
+#head1 AUTHOR
+
+I. Vlasenko, E<lt>viy@altlinux.orgE<gt>
+
+#head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2009 by I. Yu. Vlasenko.
+
+This library is free software; you can redistribute it and/or modify it under 
+either the LGPL2+ or under the same terms as Perl itself, either Perl version 5.8.4 
+or, at your option, any later version of Perl 5 you may have available.
+
+#cut
@@ -8,6 +8,7 @@
 use Test;
 BEGIN { plan tests => 1+4*8+2*7 };
 use HTML::Template::Pro;
+use lib "t";
 use HTML::Template::Pro::CommonTest;
 ok(1); # If we made it this far, we're ok.
 
@@ -14,6 +14,7 @@ BEGIN {
 }
 use File::Spec;
 use HTML::Template::Pro;
+use lib "t";
 use HTML::Template::Pro::CommonTest;
 ok(1); # If we made it this far, we're ok.
 
@@ -0,0 +1,19 @@
+#!/usr/bin/perl -w
+use Test::More no_plan;
+use HTML::Template::Pro;
+
+my $src1 =<<"END;";
+</TMPL_IF>
+<tmpl_var EXPR="(a/(foo&&&">
+<TMPL_IF NAME="foo>
+<TMPL_FI NAME="foo>
+name foo
+END;
+
+my $template1   = HTML::Template::Pro->new(scalarref => \$src1, debug=> -1);
+$template1->param(foo => 1);
+my $out=$template1->output();
+#print $out;
+ok(1); # not crashed
+
+__END__
@@ -184,7 +184,6 @@ tag_handler_include (struct tmplpro_state *state, const PSTRING* const TagOptVal
 {
   struct tmplpro_param* param;
   char* filename;
-  const char* masterpath;
   int x;
   PSTRING varvalue;
   PSTRING defvalue;
@@ -209,16 +208,17 @@ tag_handler_include (struct tmplpro_state *state, const PSTRING* const TagOptVal
   };
   if (varvalue.begin==varvalue.endnext && defvalue.begin!=defvalue.endnext) varvalue=defvalue;
   /* pstrdup */
-  filename =(char*) malloc(varvalue.endnext-varvalue.begin+1);
-  for (x=0;x<varvalue.endnext-varvalue.begin;x++) {
-    *(filename+x)=*(varvalue.begin+x);
+  {
+    const long len = varvalue.endnext-varvalue.begin;
+    filename =(char*) malloc(len+1);
+    for (x=0;x<len;x++) {
+      *(filename+x)=*(varvalue.begin+x);
+    }
+    *(filename+len)=0;
   }
-  *(filename+(varvalue.endnext-varvalue.begin))=0;
   /* end pstrdup */
-  masterpath=param->masterpath; /* saving current file name */
   tmplpro_exec_tmpl_filename (param,filename);
   free (filename);
-  param->masterpath=masterpath;
   param->cur_includes--; 
   return;
 }
@@ -1,3 +1,5 @@
 <H1> test_esc4 </H1>
  \\<>\"; %FAhidden:\r\nend 
  
+VAR1
+Some&quot;&#39; Txt&#39;
@@ -2,3 +2,5 @@
 <tmpl_iF VAR4> <tmpl_var escape="JS" DEFAULT="test failed" NAME="STUFF1"> 
 <tmpl_else> <tmpl_var DEFault="test failed" name="STUFF1" ESCApe='js'> 
 </tmpl_if> 
+<tmpl_var name='VAR1' escape='html'>
+<tmpl_var name='STUFF2' escape='html'>